package com.apes.exception;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.plugin.esb.api.EsbRouter;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.esb.processor.connector.http.HttpTransporter;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.util.Tools;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.support.TransactionTemplate;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 功能：异常消息拦截服务
 *
 * @author xul
 * @create 2020-05-18 16:51
 */
@Service
public class InterceptService {

    @Autowired
    private MessageTopicRepository messageTopicRepository;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Listener(topic = "event:invoke.exception.intercept")
    public void intercept(SimpleRequest request) {
        Message message = Tools.toBean(Message.class, request.getMap());
        transactionTemplate.execute(status -> {
            try {
                List<MessageTopic> messageTopics = messageTopicRepository.findAll(JpaDsl.toCriteriaByEq("topicType", message.getType(), "topic", message.getTopic()));
                messageTopics.addAll(messageTopicRepository.findAll(JpaDsl.toCriteriaByEq("topicType", message.getType(), "topic", "*")));
                Map<String, MessageSubscriber> messageSubscribers = new HashMap<>();
//                messageTopics.stream().forEach(messageTopic -> messageTopic.convertMessageSubscribers().stream().forEach(subscriber -> messageSubscribers.put(subscriber.getId(), subscriber)));
                Long timestamp = System.currentTimeMillis();
                messageSubscribers.forEach((k, messageSubscriber) -> {
                    String sign = sign(timestamp, messageSubscriber.getSecret());
                    String url = getUrl(messageSubscriber.getWebHook(), sign, timestamp);
                    String content = getContent(message);
                    send(url, content);
                });
                return null;
            } catch (Exception e) {
                status.isRollbackOnly();
                throw new RuntimeException(e);
            }
        });
    }

    private void send(String url, String content) {
        HttpTransporter transporter = new HttpTransporter();
        transporter.setUrl(url);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/json");
        transporter.setHeaders(headers);
        SimpleRequest request = new SimpleRequest();
        request.setData(content);
        transporter.process(request);
    }

    private String getUrl(String webhook, String sign, Long timestamp) {
        return String.format("%s&timestamp=%s&sign=%s", webhook, timestamp, sign);
    }

    private String sign(Long timestamp, String secret) {
        try {
            String stringToSign = timestamp + "\n" + secret;
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256"));
            byte[] signData = mac.doFinal(stringToSign.getBytes("UTF-8"));
            return URLEncoder.encode(new String(Base64.encodeBase64(signData)), "UTF-8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private String getContent(Message message) {
        String description = message.getType().equalsIgnoreCase("ESB") ?
                SpringManager.getBean(EsbRouter.class).getRouter(message.getTopic()).getAttribute("description") :
                message.getDescription();
        Map content = new HashMap();
        content.put("title", "异常消息");
        content.put("text", String.format("# %s「%s」「%s」\n" +
                        "**[请求]：**\n" +
                        " ```json\n" +
                        "%s\n" +
                        "```\n" +
                        "\n" +
                        "**[响应]：**\n" +
                        " ```json\n" +
                        "%s\n" +
                        "```", message.getTopic(), description,
                message.getType(),
                format(message.getRequest()), format(message.getResponse())));
        Map body = new HashMap();
        body.put("msgtype", "markdown");
        body.put("markdown", content);
        return JSON.toJSONString(body);
    }

    private String format(String text) {
        try {
            JSONObject jo = JSONObject.parseObject(text);
            return JSON.toJSONString(jo, SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue,
                    SerializerFeature.WriteDateUseDateFormat);
        } catch (Exception e) {
            return text;
        }
    }
}
